import base64
import pickle
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
from carts.models import CartRe
from carts.serializers import CartSerializer, CartgoodsSerializer, CartDeleteSerializer, CartSelectAllSerializer, \
    Cart_Put_Serializer, CartReSerializer
from goods.models import GoodsAttribute


class CartReApiView(ListAPIView):
    """购物车商品推荐"""
    serializer_class = CartReSerializer
    queryset = CartRe.objects.filter( goods__is_delete=False, goods__goods_status=1, show_status=True)[0:12]


class CartView(APIView):
    """
    购物车界面的增删改查
    """

    def perform_authentication(self, request):
        """重写检查JWT token是否正确"""
        pass

    def post(self, request):
        """保存购物车数据"""
        # 检查前端发送的数据是否正确
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        goods_id = serializer.validated_data.get('goodsattribute_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')
        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            # 前端携带了错误的 JWT  用户未登录
            user = None
        # 保存购物车数据
        if user is not None and user.is_authenticated:
            # 用户已登录 保存到redis中
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 购物车数据  hash
            pl.hincrby('cart_%s' % user.id, goods_id, count)

            # 勾选
            if selected:
                pl.sadd('cart_selected_%s' % user.id, goods_id)
            pl.execute()
            data = {'message': '添加购物车成功'}
            return Response(data=data, status=status.HTTP_201_CREATED)
            # return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            # 用户未登录，保存到cookie中
            # 尝试从cookie中读取购物车数据
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}
            # 如果有相同商品，求和
            if goods_id in cart_dict:
                origin_count = cart_dict[goods_id]['count']
                count += origin_count
            cart_dict[goods_id] = {
                'count': count,
                'selected': selected
            }
            cookie_cart = base64.b64encode(pickle.dumps(cart_dict)).decode()
            data = {'message': '添加购物车成功'}
            response = Response(data=data, status=status.HTTP_201_CREATED)
            response.set_cookie('cart', cookie_cart, max_age=60 * 60 * 24 * 30 * 365)
            return response

    def get(self, request):
        """查询购物车数据"""
        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            # 前端携带了错误的 JWT  用户未登录
            user = None
        if user is not None and user.is_authenticated:
            redis_conn = get_redis_connection('cart')
            redis_cart = redis_conn.hgetall("cart_%s" % user.id)
            cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
            cart_dict = {}
            for goods_id, count in redis_cart.items():
                cart_dict[int(goods_id)] = {
                    'count': int(count),
                    'selected': goods_id in cart_selected
                }
        else:
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}
        goods_id_list = cart_dict.keys()
        goods_obj_list = GoodsAttribute.objects.filter(id__in=goods_id_list)

        for goods in goods_obj_list:
            goods.count = cart_dict[goods.id]['count']
            goods.selected = cart_dict[goods.id]['selected']

        # 序列化返回
        serializer = CartgoodsSerializer(goods_obj_list,context={'request':self.request}, many=True)
        return Response(serializer.data)

    def put(self, request):
        # 检查前端发送的数据是否正确
        serializer = Cart_Put_Serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        goods_list = serializer.validated_data.get('goodsattribute_list')
        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            # 前端携带了错误的 JWT  用户未登录
            user = None
        if user is not None and user.is_authenticated:
            # 如果用户登录，修改redis数据
            for goods in goods_list:
                goods_id = goods['id']
                count = goods['count']
                selected = goods['selected']
                redis_conn = get_redis_connection('cart')
                pl = redis_conn.pipeline()
                pl.hset('cart_%s' % user.id, goods_id, count)
                if selected:
                    # 勾选增加记录
                    pl.sadd('cart_selected_%s' % user.id, goods_id)
                else:
                    # 未勾选 删除记录
                    pl.srem('cart_selected_%s' % user.id, goods_id)
                pl.execute()
            data = {'message': '修改购物车成功'}
            return Response(data=data, status=status.HTTP_201_CREATED)
        else:
            # 如果用户未登录，修改cookie数据
            cookie_cart_all = {}
            cart_str = request.COOKIES.get('cart')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}
            for goods in goods_list:
                goods_id = goods['id']
                count = goods['count']
                selected = goods['selected']
                if goods_id in cart_dict:
                    cart_dict[goods_id] = {
                        'count': count,
                        'selected': selected
                    }
                cookie_cart_all.update(cart_dict)
        cookie_cart = base64.b64encode(pickle.dumps(cookie_cart_all)).decode()
        data = {'message': '修改购物车成功'}
        response = Response(data=data)
        response.set_cookie('cart', cookie_cart, max_age=60 * 60 * 24 * 30 * 365)
        return response

    def delete(self, request):
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        goods_list = serializer.data.get('goodsattribute_list')
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            for goods_id in goods_list:
                redis_conn = get_redis_connection('cart')
                redis_conn.hdel('cart_%s' % user.id, goods_id)
                redis_conn.srem('cart_selected_%s' % user.id, goods_id)
            return Response({'message': '删除购物车成功'})
        else:
            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                cart = pickle.loads(base64.b64decode(cookie_str))
            else:
                cart = {}
            for goods_id in goods_list:
                if goods_id in cart.keys():
                    del cart[goods_id]
            new_cart = base64.b64encode(pickle.dumps(cart)).decode()
            data = {'message': '删除购物车成功'}
            response = Response(data=data, status=200)
            response.set_cookie('cart', new_cart, max_age=60 * 60 * 24 * 30 * 365)
            return response


class CartSelectAllView(APIView):
    """
    购物车全选，'PUT /cart/select_all/'方式发起请求，携带参数selected：TRUE\False
    """

    def perform_authentication(self, request):
        pass

    def put(self, request):
        serializer = CartSelectAllSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data['selected']
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            # 用户已登录，在redis中保存
            redis_conn = get_redis_connection('cart')
            cart = redis_conn.hgetall('cart_%s' % user.id)
            goods_id_list = cart.keys()
            if selected:
                redis_conn.sadd('cart_selected_%s' % user.id, *goods_id_list)
            else:
                redis_conn.srem('cart_selected_%s' % user.id, *goods_id_list)
            return Response({'message': 'OK'})

        else:
            # cookie
            try:
                cart_dict = request.COOKIES.get('cart')
            except:
                return Response({'message': '该用户未登录，cookie有误'})
            if cart_dict is not None:
                cart = pickle.loads(base64.b64decode(cart_dict.encode()))
                for goods_id in cart:
                    cart[goods_id]['selected'] = selected
                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                # 设置购物车的cookie
                # 需要设置有效期，否则是临时cookie
                response = Response({'message': 'OK'})
                response.set_cookie('cart', cookie_cart, max_age=60 * 60 * 24 * 30 * 365)
            else:
                response = Response({'message': '更改失败'})
            return response
